//! Traits 特性
//!
//! Trait 是 Rust 中实现抽象的重要机制，类似于其他语言中的接口。
//! 它定义了类型必须实现的功能，可以用于实现共享行为、泛型约束等。
//!
//! ## 知识点总结
//!
//! | 知识点 | 说明 | 使用场景 |
//! |--------|------|---------|
//! | Trait 定义 | 使用 trait 关键字定义接口 | 定义共享行为 |
//! | Trait 实现 | 为具体类型实现 trait | 实现特定行为 |
//! | Trait Bound | 用作泛型约束 | 泛型函数/结构体的类型限制 |
//! | Trait 对象 | 运行时多态 | 处理多种类型实现的同一 trait |
//! | 关联类型 | 在 trait 中定义占位符类型 | 简化复杂 trait 的使用 |
//! | 默认泛型参数 | 为泛型参数提供默认类型 | 增加 API 灵活性 |
//!
//! ## 关联类型（Associated Types）
//!
//! 关联类型是 trait 中的一种特殊类型占位符，它允许我们在 trait 中定义
//! 一个类型，而具体的实现者可以指定这个类型是什么。
//!
//! ### 优势
//! 1. 简化 trait 使用：不需要在使用 trait 时显式指定类型参数
//! 2. 类型安全：确保相关类型之间的一致性
//! 3. 代码清晰：避免复杂的泛型语法
//!
//! ### 示例
//! ```rust
//! trait Container {
//!     // 关联类型 Item
//!     type Item;
//!     
//!     fn insert(&mut self, item: Self::Item);
//!     fn remove(&mut self) -> Self::Item;
//! }
//! ```

/// 1. 定义 Trait
///
/// 使用 trait 关键字定义一个特性
pub trait Summary {
    /// 定义一个需要实现的方法
    fn summarize(&self) -> String;

    /// 可以提供默认实现的方法
    fn summarize_verbose(&self) -> String {
        format!("(阅读更多) {}", self.summarize())
    }
}

/// 2. 实现 Trait
///
/// 为具体类型实现特性
#[derive(Debug)]
pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

#[derive(Debug)]
pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }

    // 可以选择覆盖默认实现
    fn summarize_verbose(&self) -> String {
        format!("推文来自 {}: {}", self.username, self.content)
    }
}

/// 3. 使用 Trait
///
/// 通过 trait 对象使用实现了特定 trait 的类型
pub fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}

/// 4. Trait Bound 语法
///
/// 使用更明确的 trait bound 语法
pub fn notify_bound<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

/// 5. 通过 Trait 限制泛型
///
/// 使用 trait 作为泛型的约束条件
pub fn longest_with_an_announcement<T, U>(x: T, y: T, ann: U) -> T
where
    T: std::cmp::PartialOrd,
    U: Summary,
{
    println!("Announcement! {}", ann.summarize());
    if x > y { x } else { y }
}

/// 6. 多个 Trait Bound
///
/// 使用 + 语法指定多个 trait bound
pub fn multi_trait_bound<T: Summary + std::fmt::Display>(item: T) {
    println!("Display: {}", item);
    println!("Summary: {}", item.summarize());
}

/// 7. where 子句
///
/// 对于复杂的 trait bound，可以使用 where 子句
pub fn some_function<T, U>(t: T, u: U) -> i32
where
    T: std::fmt::Display + Clone,
    U: Clone + std::fmt::Debug,
{
    1
}

/// 8. 返回实现了 Trait 的类型
///
/// 使用 impl Trait 语法返回实现了特定 trait 的类型
pub fn returns_summarizable() -> impl Summary {
    Tweet {
        username: String::from("horse_ebooks"),
        content: String::from("of course, as you probably already know, people"),
        reply: false,
        retweet: false,
    }
}

/// 9. 使用 Trait 作为参数的替代方案
///
/// Trait 对象允许在运行时确定具体类型
pub fn notify_trait_object(item: &dyn Summary) {
    println!("News flash! {}", item.summarize());
}

/// 10. Trait 对象的限制
///
/// Trait 对象要求 trait 是对象安全的
/// 也就是说，trait 的所有方法必须满足以下条件：
/// 1. 返回类型不能是 Self
/// 2. 不能有泛型参数
pub trait Draw {
    fn draw(&self);
}

pub struct Screen {
    pub components: Vec<Box<dyn Draw>>,
}

impl Screen {
    pub fn run(&self) {
        for component in self.components.iter() {
            component.draw();
        }
    }
}

pub struct Button {
    pub width: u32,
    pub height: u32,
    pub label: String,
}

impl Draw for Button {
    fn draw(&self) {
        println!("绘制按钮: {}", self.label);
    }
}

pub struct SelectBox {
    pub width: u32,
    pub height: u32,
    pub options: Vec<String>,
}

impl Draw for SelectBox {
    fn draw(&self) {
        println!("绘制选择框，选项: {:?}", self.options);
    }
}

/// 11. 关联类型
///
/// 在 trait 中使用关联类型来指定占位符类型
pub trait Iterator {
    /// 关联类型 Item 代表迭代器产生的值的类型
    type Item;

    /// next 方法返回一个 Option<Self::Item>
    fn next(&mut self) -> Option<Self::Item>;
}

/// 12. 默认泛型类型参数
///
/// 可以为泛型类型参数指定默认值
pub trait Add<Rhs = Self> {
    type Output;

    fn add(self, rhs: Rhs) -> Self::Output;
}

/// 13. 完全限定语法
///
/// 当存在歧义时，使用完全限定语法来调用方法
pub trait Pilot {
    fn fly(&self);
}

pub trait Wizard {
    fn fly(&self);
}

pub struct Human;

impl Pilot for Human {
    fn fly(&self) {
        println!("这是机长在说话。");
    }
}

impl Wizard for Human {
    fn fly(&self) {
        println!("起飞！");
    }
}

impl Human {
    fn fly(&self) {
        println!("*挥手*");
    }
}

/// 主演示函数
pub fn demonstrate_traits() {
    println!("=== Traits 特性 ===");

    let tweet = Tweet {
        username: String::from("horse_ebooks"),
        content: String::from("of course, as you probably already know, people"),
        reply: false,
        retweet: false,
    };

    let article = NewsArticle {
        headline: String::from("Penguins win the Stanley Cup Championship!"),
        location: String::from("Pittsburgh, PA, USA"),
        author: String::from("Iceburgh"),
        content: String::from("The Pittsburgh Penguins once again are the best  hockey team in the NHL."),
    };

    println!("推文摘要: {}", tweet.summarize());
    println!("文章摘要: {}", article.summarize());
    println!("推文详细摘要: {}", tweet.summarize_verbose());
    println!("文章详细摘要: {}", article.summarize_verbose());

    // 使用 trait 作为参数
    notify(&tweet);
    notify_bound(&article);

    // 返回 impl Trait
    let summarizable = returns_summarizable();
    println!("返回的摘要: {}", summarizable.summarize());

    // Trait 对象
    let screen = Screen {
        components: vec![
            Box::new(SelectBox {
                width: 75,
                height: 10,
                options: vec![String::from("Yes"), String::from("Maybe"), String::from("No")],
            }),
            Box::new(Button { width: 50, height: 10, label: String::from("确定") }),
        ],
    };

    screen.run();

    // 完全限定语法
    let person = Human;
    person.fly(); // 调用自身的方法
    Pilot::fly(&person); // 调用 Pilot trait 的方法
    Wizard::fly(&person); // 调用 Wizard trait 的方法

    // 使用完全限定语法
    <Human as Pilot>::fly(&person);
    <Human as Wizard>::fly(&person);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_summary_trait() {
        let tweet = Tweet {
            username: String::from("test"),
            content: String::from("test content"),
            reply: false,
            retweet: false,
        };

        assert_eq!(tweet.summarize(), "test: test content");
    }

    #[test]
    fn test_notify() {
        let tweet = Tweet {
            username: String::from("test"),
            content: String::from("test content"),
            reply: false,
            retweet: false,
        };

        // 只能测试函数是否能被调用，不能测试 println! 的输出
        notify(&tweet);
    }

    #[test]
    fn test_draw_trait() {
        let button = Button { width: 10, height: 10, label: String::from("Test") };

        let select_box = SelectBox {
            width: 10,
            height: 10,
            options: vec![String::from("Option 1")],
        };

        button.draw();
        select_box.draw();
    }

    #[test]
    fn test_fully_qualified_syntax() {
        let person = Human;
        person.fly();
        Pilot::fly(&person);
        Wizard::fly(&person);
    }
}
